import { Tabs, Callout } from "nextra/components";
import UniversalTabs from "../../../../components/UniversalTabs";
import { GithubSnippet, getSnippets } from "../../../../components/code";

export const ScheduleTriggerTs = {
  path: "src/examples/scheduled-runs/programatic-schedules.ts",
};

export const ScheduleTriggerPySync = {
  path: "examples/scheduled/programatic-sync.py",
};

export const ScheduleTriggerPyAsync = {
  path: "examples/scheduled/programatic-async.py",
};

export const ScheduleTriggerGo = {
  path: "examples/scheduled/main.go",
};

export const getStaticProps = ({}) =>
  getSnippets([
    ScheduleTriggerTs,
    ScheduleTriggerPySync,
    ScheduleTriggerPyAsync,
    ScheduleTriggerGo,
  ]);

# Scheduled Runs

Scheduled runs allow you to trigger a workflow at a specific time in the future. This is useful when you need to execute a workflow at a specific time, such as sending a reminder email at a specific hour or a one-time maintenance task at a predetermined time.

Hatchet supports scheduled runs to run on a schedule defined in a few different ways:

- [Programmatically](./schedule-trigger.mdx#programmatically-creating-scheduled-runs): Use the Hatchet SDKs to dynamically set the schedule of a workflow (i.e. customer defined schedule).
- [Hatchet Dashboard](./schedule-trigger.mdx#managing-scheduled-runs-in-the-hatchet-dashboard): Manually create scheduled runs from the Hatchet Dashboard.

<Callout type="info">
  The scheduled time is when Hatchet **enqueues** the workflow, not when the run
  starts. Scheduling constraints like concurrency limits, rate limits, and retry
  policies can affect run start times.
</Callout>

## Programmatically Creating Scheduled Runs

### Create a Scheduled Run

You can create dynamic scheduled runs programmatically via the API to run workflows at a specific time in the future.

Here's an example of creating a a scheduled run to trigger a report for a specific customer tomorrow at noon:

<UniversalTabs items={["Python-Sync", "Python-Async", "Typescript", "Go"]}>
  <Tabs.Tab title="Python-Sync">
    <GithubSnippet src={ScheduleTriggerPySync} target="Create" />
  </Tabs.Tab>
  <Tabs.Tab title="Python-Async">
    <GithubSnippet src={ScheduleTriggerPyAsync} target="Create" />
  </Tabs.Tab>
  <Tabs.Tab title="Typescript">
    <GithubSnippet src={ScheduleTriggerTs} target="Create" />
  </Tabs.Tab>
  <Tabs.Tab title="Go">
    <GithubSnippet src={ScheduleTriggerGo} target="Create" />
  </Tabs.Tab>
</UniversalTabs>

In this example you can have different scheduled times for different customers, or dynamically set the scheduled time based on some other business logic.

When creating a scheduled run via the API, you will receive a scheduled run object with a metadata property containing the id of the scheduled run. This id can be used to reference the scheduled run when deleting the scheduled run and is often stored in a database or other persistence layer.

{/* Inputs and additional metadata follow the same rules as [workflow inputs](../workflows/inputs.mdx) and [additional metadata](../workflows/additional-metadata.mdx). */}

<Callout>
  Note: Be mindful of the time zone of the scheduled run. Scheduled runs are
  always stored and returned in UTC.
</Callout>

### Delete a Scheduled Run

You can delete a scheduled run by passing the scheduled run object or a scheduled run id to the delete method.

<UniversalTabs items={["Python-Sync", "Python-Async", "Typescript", "Go"]}>
  <Tabs.Tab title="Python-Sync">
    <GithubSnippet src={ScheduleTriggerPySync} target="Delete" />
  </Tabs.Tab>
  <Tabs.Tab title="Python-Async">
    <GithubSnippet src={ScheduleTriggerPyAsync} target="Delete" />
  </Tabs.Tab>
  <Tabs.Tab title="Typescript">
    <GithubSnippet src={ScheduleTriggerTs} target="Delete" />
  </Tabs.Tab>
  <Tabs.Tab title="Go">
    <GithubSnippet src={ScheduleTriggerGo} target="Delete" />
  </Tabs.Tab>
</UniversalTabs>

<Callout>
  Note: Deleting a scheduled run will not cancel any scheduled runs that have
  already entered the queue, but it will prevent future runs from starting.
</Callout>

### List Scheduled Runs

Retrieves a list of all scheduled runs matching the criteria.

<UniversalTabs items={["Python-Sync", "Python-Async", "Typescript", "Go"]}>
  <Tabs.Tab title="Python-Sync">
    <GithubSnippet src={ScheduleTriggerPySync} target="List" />
  </Tabs.Tab>
  <Tabs.Tab title="Python-Async">
    <GithubSnippet src={ScheduleTriggerPyAsync} target="List" />
  </Tabs.Tab>
  <Tabs.Tab title="Typescript">
    <GithubSnippet src={ScheduleTriggerTs} target="List" />
  </Tabs.Tab>
  <Tabs.Tab title="Go">
    <GithubSnippet src={ScheduleTriggerGo} target="List" />
  </Tabs.Tab>
</UniversalTabs>

## Managing Scheduled Runs in the Hatchet Dashboard

In the Hatchet Dashboard, you can view and manage scheduled runs for your workflows.

Navigate to "Triggers" > "Scheduled Runs" in the left sidebar and click "Create Scheduled Run" at the top right.

You can specify run parameters such as Input, Additional Metadata, and the Scheduled Time.

![Create Scheduled Run](../../../../public/schedule-dash.gif)

## Scheduled Run Considerations

When using scheduled runs, there are a few considerations to keep in mind:

1. **Time Zone**: Scheduled runs are stored and returned in UTC. Make sure to consider the time zone when defining your scheduled time.

2. **Execution Time**: The actual execution time of a scheduled run may vary slightly from the scheduled time. Hatchet makes a best-effort attempt to enqueue the workflow as close to the scheduled time as possible, but there may be slight delays due to system load or other factors.

3. **Missed Schedules**: If a scheduled workflow is missed (e.g., due to system downtime), Hatchet will not automatically run the missed instances.

4. **Overlapping Schedules**: If a workflow is still running when a second scheduled run is scheduled to start, Hatchet will start a new instance of the workflow or respect [concurrency](../concurrency/overview.mdx) policy.
